﻿#include "Camera.h"
#include <QSettings>

constexpr auto IP_LENGTH = 20;

Camera* p_camera = nullptr;

Camera::Camera(int id)
{
	p_camera = this;

	camera_id = id;

	cv::FileStorage fs("camera.yml", cv::FileStorage::READ);
	if (fs.isOpened()) {
		cv::FileNode fn = fs["camera_1"];
		camera_ip = fn["ip"];
	}

	g_semaphore = new QSemaphore(1);//相机资源锁
	//初始化相机，1秒后登录
	init_sdk();
	g_timer.setSingleShot(true);
	g_timer.setInterval(1000);
	g_timer.start();
	connect(&g_timer, &QTimer::timeout, this, [=]() {login();});
}

Camera::~Camera()
{
	//退出登录
	CLIENT_Logout(g_lLoginHandle);

	//清理sdk
	if (g_bNetSDKInitFlag)
	{
		CLIENT_Cleanup();
		g_bNetSDKInitFlag = FALSE;
	}
	//删除静态指针
	p_camera = nullptr;
	delete p_camera;
}

void Camera::init_sdk()
{
	// step1 初始化
	g_bNetSDKInitFlag = CLIENT_Init(NULL, 0);
	if (!g_bNetSDKInitFlag) {
		camera_errs.push_back("camera: init sdk failure");
		print_error("camera: init sdk failure");
	}
}

//登录
void Camera::login()
{
	const char* szUser = "admin";
	const char* szPwd = "qaz123456";

	NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stInparam;
	memset(&stInparam, 0, sizeof(stInparam));
	stInparam.dwSize = sizeof(stInparam);
	//strncpy_s(stInparam.szIP, szIp, sizeof(stInparam.szIP) - 1);
	strncpy_s(stInparam.szIP, camera_ip.data(), IP_LENGTH);
	strncpy_s(stInparam.szPassword, szPwd, sizeof(stInparam.szPassword) - 1);
	strncpy_s(stInparam.szUserName, szUser, sizeof(stInparam.szUserName) - 1);
	stInparam.nPort = 37777;
	stInparam.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;

	NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stOutparam;
	memset(&stOutparam, 0, sizeof(stOutparam));
	stOutparam.dwSize = sizeof(stOutparam);

	//step2 登录
	LLONG ret = CLIENT_LoginWithHighLevelSecurity(&stInparam, &stOutparam);
	if (ret == 0)
	{
		DWORD err = CLIENT_GetLastError();
		camera_errs.push_back("camera: login failure");
		print_error("camera login failure:%1");
	}
	else {
		g_lLoginHandle = ret;
	}

	//step3 设置捕捉回调
	if (g_lLoginHandle != 0) {

		CLIENT_SetSnapRevCallBack(SnapRev, NULL);
	}

	//step4 查询通道抓拍能力
	NET_IN_SNAP_CFG_CAPS stuSnapCapInParam = { 0 };
	stuSnapCapInParam.nChannelId = 0;
	NET_OUT_SNAP_CFG_CAPS stuSnapCapOutParam = { 0 };
	bool ret_b = CLIENT_GetDevCaps(g_lLoginHandle, NET_SNAP_CFG_CAPS, &stuSnapCapInParam, &stuSnapCapOutParam, 3000);

	//step5 取通道抓拍配置
	char* pszSnapAttr = new char[1024 * 100];
	memset(pszSnapAttr, 0, 1024 * 100);
	CFG_ENCODE_INFO stuEncodeInfo = { 0 };
	ret_b = CLIENT_GetNewDevConfig(g_lLoginHandle, (char*)CFG_CMD_ENCODE, 0, pszSnapAttr, 1024 * 100, NULL, 5000);
	//解析数据
	CLIENT_ParseData((char*)CFG_CMD_ENCODE, pszSnapAttr, (LPVOID)&stuEncodeInfo, sizeof(CFG_ENCODE_INFO), NULL);

	//step6 改变通道抓拍配置
	stuEncodeInfo.stuSnapFormat[0].abSnapEnable = true;
	stuEncodeInfo.stuSnapFormat[0].bSnapEnable = true;
	double dbFps = 0;
	if (stuSnapCapOutParam.nFramesPerSecList[0] >= 0)
	{
		dbFps = stuSnapCapOutParam.nFramesPerSecList[0];
	}
	else
	{
		dbFps = 1 / (double)(0 - stuSnapCapOutParam.nFramesPerSecList[0]);
	}
	//stuEncodeInfo.stuSnapFormat[0].stuVideoFormat.nFrameRate = (float)dbFps;
	stuEncodeInfo.stuSnapFormat[0].stuVideoFormat.nFrameRate = 1.0;
	camera_width = stuSnapCapOutParam.stuResolutionTypes[0].snWidth;
	camera_height = stuSnapCapOutParam.stuResolutionTypes[0].snHight;
	stuEncodeInfo.stuSnapFormat[0].stuVideoFormat.nWidth = stuSnapCapOutParam.stuResolutionTypes[0].snWidth;
	stuEncodeInfo.stuSnapFormat[0].stuVideoFormat.nHeight = stuSnapCapOutParam.stuResolutionTypes[0].snHight;
	stuEncodeInfo.stuSnapFormat[0].stuVideoFormat.emImageQuality = (CFG_IMAGE_QUALITY)stuSnapCapOutParam.nQualityList[5];

	if (NULL == pszSnapAttr) pszSnapAttr = new char[1024 * 100];
	memset(pszSnapAttr, 0, 1024 * 100);
	CLIENT_PacketData((char*)CFG_CMD_ENCODE, &stuEncodeInfo, sizeof(CFG_ENCODE_INFO), pszSnapAttr, 1024 * 100);
	int nError = 0;
	int nRestart = 0;
	CLIENT_SetNewDevConfig(g_lLoginHandle, (char*)CFG_CMD_ENCODE, 0, pszSnapAttr, 1024 * 100, &nError, &nRestart, 3000);

	delete[]pszSnapAttr;
	pszSnapAttr = NULL;

	//
}

//捕捉回调
void CALLBACK Camera::SnapRev(LLONG lLoginID, BYTE* pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser)
{
	cv::Mat img = cv::Mat(1080, 1920, CV_8UC1);

	if (pBuf != NULL && RevLen > 0)
	{
		uint len = RevLen;
		size_t data_size = 1080 * 1920 * sizeof(uchar);
		std::vector<uchar> data;
		data.reserve(data_size);

		for (uint i = 0;i < len;i++) {
			data.push_back(pBuf[i]);
		}
		data.shrink_to_fit();

		//uchar* buffer = (uchar*)malloc(data_size);
		//for (uint i = 0;i < len;i++) {
		//	buffer[i] = pBuf[i];
		//}
		//std::vector<uchar> data(buffer, buffer + data_size - 1);

		img = cv::imdecode(data, 0);
	}

	// 设置busy
	//qDebug() << "转换数据：" << g_counter.elapsed() << Qt::endl;

	p_camera->busy(false);
	//转发数据
	emit p_camera->sign_snap_rev(img);
	p_camera->elapsed("抓拍结束");

}
fDisConnect Camera::DisConnectFunc(LLONG lLoginID, char* pchDVRIP, LONG nDVRPort, LDWORD dwUser)
{
	return fDisConnect();
}
void Camera::elapsed(QString msg)
{
	qDebug() << msg << g_counter.elapsed() << Qt::endl;
}
//打印相机错误
void Camera::print_error(QString msg)
{
	msg += "%1";
	qDebug() << msg.arg(CLIENT_GetLastError()) << Qt::endl;
}
//捕捉
void Camera::snap()
{
	if (this->_busy) return; //阻塞
	//if (!_semaphore->tryAcquire(1, 1)) return;

	// *debug 1
	g_counter.restart();
	unsigned int nSnapType = 0;// Snapshot mode;0:request one frame,1:send out requestion regularly,2: Request consecutively
	SNAP_PARAMS stuSnapParams;
	stuSnapParams.Channel = 0;
	stuSnapParams.mode = nSnapType;
	stuSnapParams.CmdSerial = ++g_nCmdSerial;
	if (CLIENT_SnapPictureEx(g_lLoginHandle, &stuSnapParams) == false)
	{
		print_error("SnapPictureEx Failed!Last Error");
		return;
	}

	// 设置busy
	busy(true);
	g_counter.start();
}

void Camera::busy(bool state)
{
	this->_busy = state;
}

